import axios from 'axios';

export class Tools {
    /**
     * 日期格式化
     * @param {String} fmt yyyyMMdd HH:mm:ss.SSS
     * @param {Date} date
     * @returns 20190903 09:35:20.066
     */
    static dateFtt(fmt: string, date: Date) {
        let ret;
        const opt = (): { [key: string]: string } => {
            return {
                "y+": date.getFullYear().toString(),        // 年
                "M+": (date.getMonth() + 1).toString(),     // 月
                "d+": date.getDate().toString(),            // 日
                "H+": date.getHours().toString(),           // 时
                "m+": date.getMinutes().toString(),         // 分
                "s+": date.getSeconds().toString(),         // 秒
                "q+": Math.floor((date.getMonth() + 3) / 3).toString(), // 季度
                "S+": date.getMilliseconds().toString()     // 毫秒
            };
        };
        const optData = opt();
        for (let k in optData) {
            ret = new RegExp("(" + k + ")").exec(fmt);
            if (ret) {
                fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (optData[k]) : (optData[k].padStart(ret[1].length, "0")))
            }
        }
        return fmt;
    }

    /**
     * 获取不大于max的随机整数，包括0
     * @param {number} max 
     * @returns 
     */
    static getRandomInt(max: number) {
        return Math.floor(Math.random() * max);
    }

    /**
     * 生成密码
     * @param {number} len 长度
     * @param {boolean} includeSymbol 是否有“!@#$%^&*”
     * @returns 
     */
    static generatePwd(len: number, includeSymbol: boolean) {
        const chars62 = [
            '0', '1', '2', '3', '4', '5', '6', '7', '8',
            '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
            'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
            'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
            'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
            'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
        ];
        const chars70 = [
            '0', '1', '2', '3', '4', '5', '6', '7', '8',
            '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
            'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
            'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
            'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
            'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '!',
            '@', '#', '$', '%', '^', '&', '*'
        ];
        const symbolChars = ['!', '@', '#', '$', '%', '^', '&', '*'];
        const pwd = [];
        if (includeSymbol) {
            let symbolChar;
            for (let i = 0; i < len; i++) {
                const val = chars70[this.getRandomInt(chars70.length)];
                pwd.push(val);
                if (symbolChars.includes(val)) {
                    symbolChar = val;
                }
            }
            //如果生成的数据中没有符号，则随机选取一个符号随机替换一个
            if (!symbolChar) {
                symbolChar = symbolChars[this.getRandomInt(8)];
                pwd[this.getRandomInt(len)] = symbolChar;
            }
        } else {
            for (let i = 0; i < len; i++) {
                pwd.push(chars62[this.getRandomInt(chars62.length)]);
            }
        }
        return pwd.join("");
    }
}

interface Function<T> {
    (val: T): T;
}

export class Optional<T> {
    private val: T;
    constructor(val: T) {
        this.val = val;
    }

    static ofNullable<T>(val: any) {
        return new Optional<T>(val);
    }

    get() {
        return this.val;
    }

    isEmpty() {
        if (typeof this.val == "number") {
            return this.val == 0 ? false : !this.val;
        }
        return !this.val;
    }

    map(f: Function<T>) {
        return this.isEmpty() ? new Optional<T>(this.val) : new Optional<T>(f(this.val));
    }

    orElse(defaultVal: T) {
        return this.isEmpty() ? defaultVal : this.val;
    }
}

export interface Folder {
    id?: number;
    name?: string;
}
export type FolderWin = -1 | 1 | 0; //-1:删除文件夹；1:新增文件夹；0:不做任何更改

export interface Details {
    id?: number | null;
    title?: string;
    username?: string;
    pwd?: string;
    addr?: string;//地址
    memo?: string;//备注
    folderId?: number | null;//文件夹id
    deleted?: number;//1：删除；0：正常
    star?: number;//1：收藏；0：没收藏
    updateTime?: string;
    sn?: number; //排序号
}
export type DetailsWin = 0 | 1 | 2; //0:没有任何窗口；1:详情窗口；2:编辑窗口

export interface Version {
    one: string;
    two: string;
    three: string;
}

interface ApiParam<T> {
    path?: string;
    data?: T;
    timeout?: number;
    headers?: any;
}
interface ApiErrorResult {
    code: 1 | -1; //1:接口错误 -1:超时、错误、中断、返回值解析错误都会进入，无法判断业务是否真的失败
    msg: string; //错误信息
}
class Api {
    private url: string = "/api";

    /**
     * T：入参data的类型
     * @param Obj 
     * @returns 
     */
    private request<T>(Obj: ApiParam<T>) {
        const { path = "", data = {}, timeout = 1000 * 60 } = Obj;
        return axios({
            method: 'post',
            url: this.url + path,
            data: data,
            timeout: timeout,
            headers: Obj.headers
        });
    }

    /**
     * T:resolve的类型
     * S:入参data的类型
     * @param Obj 
     * @returns 
     */
    protected return<T, S>(Obj: ApiParam<S>) {
        return new Promise<T>(async (resolve, reject: (val: ApiErrorResult) => void) => {
            try {
                let json = await this.request<S>(Obj);
                //json.data => AppResultDto
                let status = json.data.status;
                if (status === "SUCCESS") {
                    resolve(json.data.data);
                } else {
                    reject(this.error({
                        code: 1,
                        msg: Obj.path + "接口调用异常，" + json.data.msg
                    }));
                }
            } catch (error) {
                //超时、错误、中断、返回值解析错误都会进入，无法判断业务是否真的失败
                reject(this.error({
                    code: -1,
                    msg: Obj.path + "请求错误，" + error
                }));
            }
        });
    }

    private error(info: ApiErrorResult): ApiErrorResult {
        return {
            code: info.code,
            msg: info.msg
        }
    }
}

/**
 * 后端接口调用
 */
export class PwdmApi extends Api {

    /**
     * 获取版本信息
     * @returns 
     */
    version() {
        return super.return<Version, void>({
            path: "/version"
        });
    }

    /**
     * 登录
     * @param username 
     * @param pwd 
     * @returns 登录成功返回用户名"admin"
     */
    signIn(username: string, pwd: string) {
        return super.return<void, string>({
            path: `/login?username=${username}&password=${pwd}`
        });
    }

    signOut() {
        return super.return<void, void>({
            path: "/logout"
        });
    }

    /**
     * 获取登录状态
     * @returns 登录成功返回用户名"admin"
     */
    auth() {
        return super.return<void, string>({
            path: "/auth"
        });
    }

    /**
     * 修改密码
     * @param oldPwd 
     * @param newPwd 
     * @returns 
     */
    chgPwd(oldPwd: string, newPwd: string) {
        return super.return<void, void>({
            path: `/chg/pwd?oldPwd=${oldPwd}&newPwd=${newPwd}`
        });
    }

    folderList() {
        return super.return<Folder[], Folder>({
            path: "/folder/list"
        });
    }

    folderQuery(id: number) {
        return super.return<Folder, Folder>({
            path: "/folder/query",
            data: {
                id: id
            }
        });
    }

    folderAdd(name: string) {
        return super.return<Folder, Folder>({
            path: "/folder/add",
            data: {
                name: name
            }
        });
    }

    folderDel(id: number) {
        return super.return<null, Folder>({
            path: "/folder/del",
            data: {
                id: id
            }
        });
    }

    detailsList(p: Details) {
        return super.return<Details[], Details>({
            path: "/details/list",
            data: {
                folderId: p.folderId,
                star: p.star,
                deleted: p.deleted
            }
        });
    }

    detailsSave(p: Details) {
        return super.return<Details, Details>({
            path: "/details/save",
            data: p
        });
    }

    detailsDelete(p: Details) {
        return super.return<void, Details>({
            path: "/details/delete",
            data: p
        });
    }
}